﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


namespace Fusion
{
    /// <summary> Base collision solid, axis-aligned bounding box. </summary>
    public class Solid
    {
        #region Fields

		public Entity container;
        
		// Dimensional bounds
		// These basics oughta be kept in Entity
        public Vector2 center;
		public Vector2 size;
		public Vector2 Center
		{
			get
			{
				if( container == null )
					return center;
				else
					return center + container.Position;
			}
			set
			{
				if( container == null )
					center = value;
				else
					center = value - container.Position;
			}
		}
		public Vector2 Size
		{
			get
			{
				if( container == null )
					return size;
				else
					return size * container.Scale;
			}
			set
			{

				if( container == null )
					size = value;
				else
					size = value / container.Scale;
			}
		}

        public Vector2 TL
        {
            get
			{
				return Center - ( Size / 2 );
            }
        }
        public Vector2 TR
		{
			get
			{
				Vector2 tr = Center - ( Size / 2 );
				tr.X *= -1;
				return tr;
			}
        }
        public Vector2 BL
        {
			get
			{
				Vector2 bl = Center + ( Size / 2 );
				bl.X *= -1;
				return bl;
			}
        }
        public Vector2 BR
		{
			get
			{
				return Center + ( Size / 2 );
			}
        }

		// Physical properties
		public float surfaceFriction = 1.0f;

        #endregion
        
        #region Constructors

        /// <summary> Blank Constructor </summary>
        public Solid( Entity cont )
        {
			container = cont;
        }

        /// <summary> Creates an AA box of width,height </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public Solid( Entity cont , float width, float height )
		{
			container = cont;
			size = new Vector2( width, height );
			center = Vector2.Zero;
        }

        /// <summary> Copy Constructor </summary>
        public Solid( Solid original )
        { Copy( original ); }

        /// <summary> Copies the original shape</summary>
        /// <param name="from">Shape to copy from</param>
        public virtual void Copy( Solid original )
        {
            container = original.container;

			center = original.center;
			size = original.size;
        }

        /// <summary> Returns a clone </summary>
        public virtual Solid Clone()
        { return new Solid( this ); }

        #endregion

		#region Methods

		public void Draw()
		{
			UI.DrawBox( Center - new Vector2(0.5f,0.5f), Size - Vector2.One, Color.Red );
		}

		public virtual bool Intersect( Entity test, ref Vector2 projection )
		{
			if( test is Prop )
				return Intersect( ( test as Prop ).solid, ref projection );
			else
				return Hax.Intersect( test.Position, test.Size, Center, Size, ref projection );
		}

		/// <summary> Tests if this shape intersects another </summary>
		/// <param name="test">The shape to test with</param>
		/// <param name="projection">The projection distance from the nearest edge to the intersection</param>
		/// <returns>True if the shapes intersect, else False</returns>
		public virtual bool Intersect( Solid test, ref Vector2 projection )
		{
			// Don't touch yourself
			if( test == this )
				return false;

			// Add things for more complex shapes here
			// if( test is Circle ) //etc
			return Hax.Intersect( test.Center, test.Size, Center, Size, ref projection );
		}

        /// <summary> Test if a point is contained within this shape </summary>
        /// <param name="point">The point to test</param>
		/// <param name="projection">The projection distance from the nearest edge to the intersection</param>
        /// <returns>True if point is inside this shape, eles False</returns>
        public virtual bool Intersect( Vector2 point, ref Vector2 projection )
        {
			return Hax.Intersect( point, Center, Size, ref projection );
        }

		/// <summary> Tests intersection with a specified AA box </summary>
		/// <param name="boxCenter">Center of the test box</param>
		/// <param name="boxSize">Size of the test box</param>
		/// <param name="projection">The projection distance from the nearest edge to the intersection</param>
		/// <returns></returns>
		public virtual bool Intersect( Vector2 boxCenter, Vector2 boxSize, ref Vector2 projection )
		{
			return Hax.Intersect( boxCenter, boxSize, Center, Size, ref projection );
		}

		/// <summary> Tests intersection with a line </summary>
		/// <param name="from">Line start</param>
		/// <param name="to">Line end</param>
		/// <param name="point">Intersection point</param>
		/// <param name="slice">Intersection percent</param>
		/// <returns>True if the line intersects</returns>
		public virtual bool Intersect( Vector2 from, Vector2 to, ref Vector2 point, ref float slice )
		{
			float minSlice = float.MaxValue;
			bool intersected = false;

			if( Line.Intersects( from, to, TL, TR, ref slice, ref point ) == true )
			{
				intersected = true;
				if( slice < minSlice )
					minSlice = slice;
			}
			if( Line.Intersects( from, to, TR, BR, ref slice, ref point ) == true )
			{
				intersected = true;
				if( slice < minSlice )
					minSlice = slice;
			}
			if( Line.Intersects( from, to, BR, BL, ref slice, ref point ) == true )
			{
				intersected = true;
				if( slice < minSlice )
					minSlice = slice;
			}
			if( Line.Intersects( from, to, BL, TL, ref slice, ref point ) == true )
			{
				intersected = true;
				if( slice < minSlice )
					minSlice = slice;
			}

			slice = minSlice;
			return intersected;
		}

        #endregion
    }
}
